package demo2

import (
	"fmt"
)

/*
	方法和接收器
	  1. Go 方法是作用在接收器（receiver）上的一个函数，接收器是某种类型的变量。因此方法是一种特殊类型的函数。
		2. 接收器类型可以是（几乎）任何类型，不仅仅是结构体类型,
			但是接收器不能是一个接口类型，因为接口是一个抽象定义，但是方法却是具体实现
		3. 接收器不能是一个指针类型，但是它可以是任何其他允许类型的指针。
		4. 在 Go语言中，类型的代码和绑定在它上面的方法的代码可以不放置在一起，
			它们可以存在在不同的源文件，唯一的要求是：它们必须是同一个包的。
		5. 类型 T（或 T）上的所有方法的集合叫做类型 T（或 T）的方法集。
		6. 因为方法是函数，所以同样的，不允许方法重载，即对于一个类型只能有一个给定名称的方法。
			但是如果基于接收器类型，是有重载的：具有同样名字的方法可以在 2 个或多个不同的接收器类型上存在，比如在同一个包里这么做是允许的。
		7. 接收器 -- 方法作用的目标
			func (接收器变量 接收器类型) 方法名(参数列表) (返回参数) {
				函数体
			}
			7.1 接收器变量：接收器中的参数变量名在命名时，官方建议使用接收器类型名的第一个小写字母，而不是 self、this 之类的命名。
					例如，Socket 类型的接收器变量应该命名为 s，Connector 类型的接收器变量应该命名为 c 等。
			7.2 接收器类型：接收器类型和参数类似，可以是指针类型和非指针类型。
			7.3 方法名、参数列表、返回参数：格式与函数定义一致。
*/

/* demo1 */

// Bag 书包
type Bag struct {
	items []int
}

// 1. 面向对象： 将一个物品放入背包的过程
func insertToBag(b *Bag, itemid int) {
	b.items = append(b.items, itemid)
}

// 2. 结构体方法： 将一个物品放入背包的过程
// 	2.1 (b *Bag) 是方法 insertToBag2 的接收器
// 	2.2 每个方法只能有一个接收器
// 	2.3 调用方法： b.insertToBag2(itemid)
func (b *Bag) insertToBag2(itemid int) {
	b.items = append(b.items, itemid)
}

/* demo2 */

// Property 属性
type Property struct {
	value int // 属性值
}

// 设置属性值
func (p *Property) setValue(v int) {
	// 修改成员变量
	p.value = v
}

// 取属性值
func (p *Property) getValue() int {
	return p.value
}

// Point 点
type point struct {
	X int
	Y int
}

// 分指针类型接收器的加方法
func (p point) add(other point) point {
	// 成员值与参数相加后返回新的结构
	return point{p.X + other.X, p.Y + other.Y}
}

// TestDemo211 方法和接收器测试
func TestDemo211() {

	/*
		demo1: 结构体添加方法
	*/
	// demo11: 面向对象的实现
	bag1 := new(Bag)
	insertToBag(bag1, 1001)

	fmt.Println(bag1)
	// demo12: go 语言的结构体方法
	bag2 := new(Bag)
	bag2.insertToBag2(1002)
	fmt.Println(bag2)

	/*
		demo2: 接收器根据接收器的类型可以分为指针接收器、非指针接收器。
			两种接收器在使用时会产生不同的效果。根据效果的不同，两种接收器会被用于不同性能和功能要求的代码中。
	*/
	// demo21: 指针类型的接收器
	//    1. 指针类型的接收器由一个结构体的指针组成，更接近于面向对象中的 this 或者 self。
	//		2. 由于指针的特性，调用方法时，修改接收器指针的任意成员变量，在方法结束后，修改都是有效的。
	p1 := new(Property)
	// 设置值
	p1.setValue(111)
	// 打印值
	fmt.Println(p1.getValue())
	fmt.Println(p1)

	// demo22: 非指针类型的接收器
	//		1. 当方法作用于非指针接收器时，Go语言会在代码运行时将接收器的值复制一份。
	//			在非指针接收器的方法中可以获取接收器的成员值，但修改后无效。
	// 初始化点
	point1 := point{1, 1}
	point2 := point{2, 2}
	// 与另外一个点相加
	result := point1.add(point2)
	// 输出结果
	fmt.Println(result)
}
